from django.db import models

from courses.models import Course, Profile
from django.core.cache import cache

from courses.apps import App

#set the course.chat variable with all the necessary goodies
class CourseChatRoom(App):
    
    @property
    def URL_ROOT(self):
        return self._course.url + 'chat/'
    
    @property
    def AJAX_ROOT(self):
        return self.URL_ROOT + 'ajax/'
    
    CACHE_MAX = 5 #how many messages to cache
    CACHE_TIMEOUT = 20 #how long to store the cache, in seconds
    
    @property
    def CACHE_KEY(self):
        return 'chat_messages_'+str(self._course.id)

    def get_cache(self):
        return cache.get(self.CACHE_KEY, [])
    
    def last_cid(self):
        cached = self.get_cache()
        if cached:
            return cached[-1]['id']
        try:
            #get the last index for this course; hit the db for one row
            print 'hitting database for last_cid...'
            return Message.objects.filter(
                course=self._course).order_by('-cid')[0].cid
        except IndexError:
            #no messages!
            return 0
        
        
    def update_cache(self, message):
        print 'updating cache...',
        message.set_cid()
        cache.set(self.CACHE_KEY, 
            (self.get_cache() + [message.__json__()])[-self.CACHE_MAX:],
            self.CACHE_TIMEOUT
        )
        print 'Done.'
            
    @property
    def getMessagesUrl(self):
        return self.AJAX_ROOT + 'get_messages/'
    
    @property
    def postMessageUrl(self):
        return self.AJAX_ROOT + 'post_message/'
    
    @property
    def getCachedMessagesUrl(self):
        return self.AJAX_ROOT + 'get_cached_messages/'
    
    def postMessage(self, profile, content, timestamp=None):
        if timestamp is None:
            import datetime
            timestamp = datetime.datetime.now()
        elif isinstance(timestamp, int):
            import datetime
            timestamp = datetime.fromtimestamp(timestamp)
        
        print 'attempting to post the following message:'
        print 'course: %s' % self._course
        print 'user: %s' % profile
        print 'content: %s' % content
        print 'timestamp: %s' % timestamp
        
        m = Message(course=self._course, user=profile, 
            content=content, timestamp=timestamp
        )
        self.update_cache(m)
        
        print 'Saving...',
        m.save()
        print 'Done.'
        #update the cache
        
        return m
        
    def getMessages(self, last_id):    
        if last_id is None:
            #get the last 10 messages
            all_messages = self._course.chat_messages.all().order_by('-cid')
            return all_messages[:10][::-1] 
            #done in two steps because [::-1] queries the db.
        else:
            #get all messages since last_id
            return self._course.chat_messages.filter(cid__gt=long(last_id))
    
    def getCachedMessages(self, last_id = None):
        cached = self.get_cache()
        
        #if the cache is empty, hit the db
        if not cached:
            return [m.__json__() for m in self.getMessages(last_id)]
        
        last_id = last_id or 0
        print 'cached messages: %s' % cached
        print 'last_id = %s' % last_id
        print 'breakdown: %s' % [(m['id'], m['id'] > long(last_id)) for m in cached]
        latest = [m for m in cached if m['id'] > long(last_id)]
        print 'latest: %s' % latest
        
        return latest
    
    def getLastMessages(self, num, until_id=None):
        #this line's a doozy.  We get the queryset, order in reverse, slice it,
        #then evaluate to a list (i.e. execute the sql), then reverse it with
        #python
        kws = {'course':self._course}
        if not until_id is None:
            kws.update(cid__lt=until_id)
        return [m for m in
            Message.objects.filter(**kws).order_by('-cid')[:num]
        ]

class Message(models.Model):
    course = models.ForeignKey(Course, related_name='chat_messages', editable=False)
    timestamp = models.DateTimeField(auto_now_add=True, editable=False)
    user = models.ForeignKey(Profile, editable=False)
    
    cid = models.IntegerField(editable=False, default=0) #id within the course.  see save() below.
    
    content = models.CharField(max_length=255) #was 1000, changed for mysql 4.1.22
    
    def __repr__(self):
        return '<In %s, %s said "%s"; cid=%s>' % (
            self.course,
            self.user,
            self.content,
            self.cid,
        )
    
    #see the simplerjson module
    def __json__(self):
        return {
            'id': self.cid,
            'user': self.user.user.username,
            'content': self.content,
            'timestamp': tuple(self.timestamp.timetuple()),
        }
    
    def set_cid(self):
        if self.cid == 0:
            self.cid = 1 + self.course.chat.last_cid()
    
    def save(self, *args, **kwargs):
        self.set_cid()
        super(Message, self).save(*args, **kwargs)
